package com.elephant.core.utils;


import net.sf.json.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.springframework.util.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * @author: hai
 * @description:
 * @date: 13:31 2018/9/30
 */
public class EncryptUtile {

	private static Cipher cipher;
	private static SecretKeySpec key;
	private static AlgorithmParameterSpec spec;
	private static final String SEED_16_CHARACTER = "T15jPCM09OOUO.QO";

	static {
		// hash password with SHA-256 and crop the output to 128-bit for key
		MessageDigest digest = null;
		try {
			digest = MessageDigest.getInstance("SHA-256");
			digest.update(SEED_16_CHARACTER.getBytes("UTF-8"));
			byte[] keyBytes = new byte[32];
			System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length);
			cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
			key = new SecretKeySpec(keyBytes, "AES");
			spec = getIV();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}

	}

	public static AlgorithmParameterSpec getIV() {
		byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
		IvParameterSpec ivParameterSpec;
		ivParameterSpec = new IvParameterSpec(iv);
		return ivParameterSpec;
	}

	public static String encrypt(String plainText) throws Exception {
		cipher.init(Cipher.ENCRYPT_MODE, key, spec);
		byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));
		String encryptedText = new String(Base64.encodeBase64(encrypted),
				"UTF-8");
		return encryptedText;
	}

	public static String decrypt(String cryptedText) throws Exception {
		cipher.init(Cipher.DECRYPT_MODE, key, spec);
		byte[] bytes = Base64.decodeBase64(cryptedText);
		byte[] decrypted = cipher.doFinal(bytes);
		String decryptedText = new String(decrypted, "UTF-8");
		return decryptedText;
	}

	public static JSONObject parseJson(String info) throws Exception {
		JSONObject json = JSONObject.fromObject(EncryptUtile.decrypt(info));
		return json;
	}

	public static String encrypt(String plainText,String salt) throws Exception {
		Cipher cipherSalt = Cipher.getInstance("AES/CBC/PKCS5Padding");
		cipherSalt.init(Cipher.ENCRYPT_MODE, getKey(salt), spec);
		byte[] encrypted = cipherSalt.doFinal(plainText.getBytes("UTF-8"));
		String encryptedText = new String(Base64.encodeBase64(encrypted),
				"UTF-8");
		return encryptedText;
	}

	public static String decrypt(String cryptedText,String salt) throws Exception {
		Cipher cipherSalt = Cipher.getInstance("AES/CBC/PKCS5Padding");
		cipherSalt.init(Cipher.DECRYPT_MODE, getKey(salt), spec);
		byte[] bytes = Base64.decodeBase64(cryptedText);
		byte[] decrypted = cipherSalt.doFinal(bytes);
		String decryptedText = new String(decrypted, "UTF-8");
		return decryptedText;
	}

	public static JSONObject parseJson(String info,String salt) throws Exception {
		JSONObject json = JSONObject.fromObject(EncryptUtile.decrypt(info,salt));
		return json;
	}

	private static SecretKeySpec getKey (String salt) {
		MessageDigest digest = null;
		try {
			StringBuilder sb = new StringBuilder(SEED_16_CHARACTER);
			sb.insert(5,salt);
			digest = MessageDigest.getInstance("SHA-256");
			digest.update(sb.toString().getBytes("UTF-8"));
			byte[] keyBytes = new byte[32];
			System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length);
			return new SecretKeySpec(keyBytes, "AES");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return null;
	}

	public static Map<String,Object> getEncryptInfo(JSONObject json) throws Exception {
		Map<String,Object> param = new HashMap(2);
		Long timestamp = System.currentTimeMillis();
		json.put("timestamp",timestamp);
		param.put("info", EncryptUtile.encrypt(json.toString(), String.valueOf(timestamp)));
		param.put("timestamp", String.valueOf(timestamp));
		return param;
	}

	public static JSONObject parseApi(JSONObject json) throws Exception {
		if (json.containsKey("status") && json.getString("status").equals("OK")) {
			if (json.containsKey("message")) {
				return json.getJSONObject("message");
			}
		} else if (json.containsKey("status") && json.getString("status").equals("ERROR")) {
			throw new Exception(json.getString("message"));
		}
		return null;
	}

	public static JSONObject parseApi(JSONObject json,String timestamp) throws Exception {
		if (json.containsKey("status") && json.getString("status").equals("OK")) {
			if (json.containsKey("message")) {
				String info = EncryptUtile.decrypt(json.getString("message"),timestamp);
				return JSONObject.fromObject(info);
			}
		} else if (json.containsKey("status") && json.getString("status").equals("ERROR")) {
			throw new Exception(json.getString("message"));
		}
		return null;
	}

	public static JSONObject parseEncryptApi(JSONObject json) throws Exception {
		if (json.containsKey("status") && json.getString("status").equals("OK")) {
			if (json.containsKey("message")) {
				return EncryptUtile.parseJson(json.getString("message"));
			}
		} else if (json.containsKey("status") && json.getString("status").equals("ERROR")) {
			throw new Exception(json.getString("message"));
		}
		return null;
	}

	public static void main(String[] args) {
		try {
//			System.out.println(decrypt("Y4DFEuYYvRO6aCOeDzKBBAiYSeMVN7/wuEb0UjC127rgUTAZ53CijLWBtCAlXYlI30lMKQ1vIYCAhGyFQvFJpefA7J0EucHhrHiRTJOet4oUiBRzhLT3pFeIjDCFQldmpuuuy/qSEkTfHG5fJ6LcSg=="));

			System.out.println("啧啧啧".length()>256?"啧啧啧".substring(0,256):"啧啧啧");
			System.out.println("啧啧啧".getBytes("UTF-8").length);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
